/* eslint-disable @typescript-eslint/ban-types */
import { batch } from './singals';

export const EFFECT_KEY = Symbol('effect');

export const DISPOSE_KEY = Symbol('effect_dispose');

export const SSCLASS_KEY = Symbol('ssclass');

// 是添加了@ssclass装饰器的组件
export function isSSComponent(obj: any) {
    return obj && obj[SSCLASS_KEY];
}

export function safeCall(fn: any, self: any, ...args: any[]) {
    if (typeof fn === 'function') {
        try {
            return fn.apply(self, args);
        } catch (error) {
            console.warn('[safeCall] Error executing function:', error);
            return undefined;
        }
    }
    return undefined;
}

export const noop = () => {};

export function isPrimitive(value: any) {
    return (
        typeof value === 'string'
      || typeof value === 'number'
      || typeof value === 'boolean'
      || typeof value === 'symbol'
      || typeof value === 'bigint'
      || value === null
      || value === undefined
    );
}

export function isPlainObject(value: unknown): boolean {
    return (
        value !== null
        && typeof value === 'object'
        && Object.prototype.toString.call(value) === '[object Object]'
    );
}

let $sequence = 0;
export function getSequence() {
    return $sequence++;
}

export function isFunction(val: unknown): val is Function {
    return typeof val === 'function';
}

export function buildBatchUpdate(batcher: (cb: () => void) => void) {
    const callbacks = new Set<() => void>();
    let pending = false;

    function flushCallbacks() {
        pending = false;
        const copies = Array.from(callbacks);
        callbacks.clear();
        batcher(() => {
            copies.forEach((cb) => {
                try {
                    cb();
                } catch (error) {
                    console.warn('[buildBatchUpdate] Error in callback:', error);
                }
            });
        });
    }

    function emit(cb: () => void) {
        callbacks.add(cb);

        if (!pending) {
            pending = true;
            Promise.resolve().then(flushCallbacks);
        }
    }

    return emit;
}

export function get(obj: any, path: string, defaultValue?: any) {
    // 参数验证
    if (obj === null || obj === undefined) {
        return defaultValue;
    }

    if (typeof path !== 'string' || path.trim() === '') {
        return obj;
    }

    try {
        const paths = path.split('.');
        let target = obj;

        for (const p of paths) {
            // 跳过空路径段
            if (p.trim() === '') {
                continue;
            }

            // 检查目标是否为 null 或 undefined
            if (target === null || target === undefined) {
                return defaultValue;
            }

            // 检查目标是否为对象或数组
            if (typeof target !== 'object') {
                return defaultValue;
            }

            // 安全地获取属性值
            target = target[p];
        }

        return target !== undefined ? target : defaultValue;
    } catch (error) {
        console.warn(`[get] Error accessing path "${path}":`, error);
        return defaultValue;
    }
}

/**
 * 安全地设置对象属性值
 * @param obj 目标对象
 * @param path 属性路径
 * @param value 要设置的值
 * @returns 是否设置成功
 */
export function set(obj: any, path: string, value: any): boolean {
    // 参数验证
    if (obj === null || obj === undefined) {
        console.warn('[set] Cannot set property on null or undefined object');
        return false;
    }

    if (typeof path !== 'string' || path.trim() === '') {
        console.warn('[set] Invalid path provided');
        return false;
    }

    try {
        const paths = path.split('.');
        let target = obj;

        // 遍历到倒数第二个路径段
        for (let i = 0; i < paths.length - 1; i++) {
            const p = paths[i];

            // 跳过空路径段
            if (p.trim() === '') {
                continue;
            }

            // 如果当前目标不存在，创建一个空对象
            if (target[p] === null || target[p] === undefined) {
                target[p] = {};
            }

            // 检查目标是否为对象
            if (typeof target[p] !== 'object') {
                console.warn(`[set] Cannot set property on non-object at path "${paths.slice(0, i + 1).join('.')}"`);
                return false;
            }

            target = target[p];
        }

        // 设置最后一个属性
        const lastPath = paths[paths.length - 1];
        if (lastPath.trim() !== '') {
            target[lastPath] = value;
            return true;
        }

        return false;
    } catch (error) {
        console.warn(`[set] Error setting path "${path}":`, error);
        return false;
    }
}

export function shallowSet(state: any, path: string, value: any) {
    if (state === null || state === undefined) {
        console.warn('[shallowSet] Cannot set property on null or undefined object');
        return false;
    }

    if (typeof path !== 'string' || path.trim() === '') {
        console.warn('[shallowSet] Invalid path provided');
        return false;
    }

    const paths = path.split('.');
    if (paths.length === 1) {
        state[path] = value;
        return true;
    }

    const topPath = paths[0];
    const prop = state[topPath];

    const np = Array.isArray(prop) ? [...prop] : { ...prop };
    set(np, paths.slice(1).join('.'), value);
    state[topPath] = np;

    return true;
}

export function merge(target: any, ...sources: any[]) {
    if (!target || !sources.length) return target;
    
    const visited = new WeakSet(); // 用于检测循环引用
    
    function mergeObject(target: any, source: any): void {
      if (!isPlainObject(target) || !isPlainObject(source)) {
        return;
      }
      
      // 检查循环引用
      if (visited.has(source)) {
        return; // 跳过循环引用
      }
      visited.add(source);
      
      for (const key in source) {
        if (source.hasOwnProperty(key)) {
          if (isPlainObject(source[key])) {
            if (!isPlainObject(target[key])) {
              target[key] = {};
            }
            mergeObject(target[key], source[key]);
          } else {
            target[key] = source[key];
          }
        }
      }
      
      visited.delete(source); // 清理，允许在其他分支中重新访问
    }
    
    for (const source of sources) {
      mergeObject(target, source);
    }
    
    return target;
}

export function deepClone<T = any>(obj: T): T {
    if (obj === null || typeof obj !== 'object') {
      return obj;
    }
  
    const visited = new WeakMap<object, any>(); // 用于检测循环引用
    
    function clone(original: any): any {
      // 基本类型直接返回
      if (original === null || typeof original !== 'object') {
        return original;
      }
      
      // 检查循环引用
      if (visited.has(original)) {
        return visited.get(original);
      }
      
      let cloned: any;
      
      // 处理不同类型的对象
      if (Array.isArray(original)) {
        cloned = [];
        visited.set(original, cloned);
        for (let i = 0; i < original.length; i++) {
          cloned[i] = clone(original[i]);
        }
      } else if (original instanceof Date) {
        cloned = new Date(original.getTime());
        visited.set(original, cloned);
      } else if (original instanceof RegExp) {
        cloned = new RegExp(original.source, original.flags);
        visited.set(original, cloned);
      } else if (original instanceof Map) {
        cloned = new Map();
        visited.set(original, cloned);
        for (const [key, value] of original.entries()) {
          cloned.set(clone(key), clone(value));
        }
      } else if (original instanceof Set) {
        cloned = new Set();
        visited.set(original, cloned);
        for (const value of original.values()) {
          cloned.add(clone(value));
        }
      } else if (original instanceof Error) {
        cloned = new (original.constructor as any)(original.message);
        visited.set(original, cloned);
        cloned.stack = original.stack;
        cloned.name = original.name;
      } else {
        // 普通对象
        cloned = Object.create(Object.getPrototypeOf(original));
        visited.set(original, cloned);
        
        for (const key of Reflect.ownKeys(original)) {
          const descriptor = Object.getOwnPropertyDescriptor(original, key);
          if (descriptor) {
            if (descriptor.value !== undefined) {
              cloned[key] = clone(descriptor.value);
            } else {
              // 处理 getter/setter
              Object.defineProperty(cloned, key, descriptor);
            }
          }
        }
      }
      
      return cloned;
    }
    
    return clone(obj);
}

interface PathInfo {
    stateId: string
    paths: string[]
    subpath: string
}

/**
 * 解析状态访问路径，返回状态ID和子路径
 * @param path 访问路径
 * @returns 路径信息
 */
export function parsePath(path: string): PathInfo | null {
    if (typeof path !== 'string' || path.trim() === '') {
        return null;
    }

    const paths = path.split('.');
    const stateId = paths[0];
    const subpath = paths.slice(1).join('.');

    return { stateId, paths, subpath };
}